<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>浅谈React Fiber工作原理 | 技术文档</title>
    <meta name="generator" content="VuePress 1.9.9">
    
    <meta name="description" content="technology-review">
    <meta name="theme-color" content="#3eaf7c">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    
    <link rel="preload" href="/tech-document/assets/css/0.styles.afad9826.css" as="style"><link rel="preload" href="/tech-document/assets/js/app.7336957d.js" as="script"><link rel="preload" href="/tech-document/assets/js/2.4e1184b4.js" as="script"><link rel="preload" href="/tech-document/assets/js/4.254b04cb.js" as="script"><link rel="preload" href="/tech-document/assets/js/12.c2ba2865.js" as="script"><link rel="prefetch" href="/tech-document/assets/js/10.403778a6.js"><link rel="prefetch" href="/tech-document/assets/js/11.1b3238dc.js"><link rel="prefetch" href="/tech-document/assets/js/13.10289b8b.js"><link rel="prefetch" href="/tech-document/assets/js/14.d292f43c.js"><link rel="prefetch" href="/tech-document/assets/js/15.2194d6d3.js"><link rel="prefetch" href="/tech-document/assets/js/16.42e9ba11.js"><link rel="prefetch" href="/tech-document/assets/js/17.a49afd61.js"><link rel="prefetch" href="/tech-document/assets/js/18.98476456.js"><link rel="prefetch" href="/tech-document/assets/js/19.29a251d2.js"><link rel="prefetch" href="/tech-document/assets/js/20.ca55bb01.js"><link rel="prefetch" href="/tech-document/assets/js/21.ae42376a.js"><link rel="prefetch" href="/tech-document/assets/js/22.b1bc092f.js"><link rel="prefetch" href="/tech-document/assets/js/23.38f4ebdf.js"><link rel="prefetch" href="/tech-document/assets/js/24.8c3f712c.js"><link rel="prefetch" href="/tech-document/assets/js/25.317efa81.js"><link rel="prefetch" href="/tech-document/assets/js/26.afeef7fe.js"><link rel="prefetch" href="/tech-document/assets/js/27.44fccbaf.js"><link rel="prefetch" href="/tech-document/assets/js/28.290da4aa.js"><link rel="prefetch" href="/tech-document/assets/js/29.fa50ae0a.js"><link rel="prefetch" href="/tech-document/assets/js/3.414f2d7e.js"><link rel="prefetch" href="/tech-document/assets/js/30.88d887a4.js"><link rel="prefetch" href="/tech-document/assets/js/31.567937c9.js"><link rel="prefetch" href="/tech-document/assets/js/32.27fa7a1a.js"><link rel="prefetch" href="/tech-document/assets/js/33.4eb80605.js"><link rel="prefetch" href="/tech-document/assets/js/34.cf229122.js"><link rel="prefetch" href="/tech-document/assets/js/35.945a7237.js"><link rel="prefetch" href="/tech-document/assets/js/36.d0a4767e.js"><link rel="prefetch" href="/tech-document/assets/js/37.4c6954a0.js"><link rel="prefetch" href="/tech-document/assets/js/38.2bccf61b.js"><link rel="prefetch" href="/tech-document/assets/js/39.2040339f.js"><link rel="prefetch" href="/tech-document/assets/js/40.cc2c8a0d.js"><link rel="prefetch" href="/tech-document/assets/js/41.61cf17ce.js"><link rel="prefetch" href="/tech-document/assets/js/42.b38eb7ca.js"><link rel="prefetch" href="/tech-document/assets/js/43.4ea8ba50.js"><link rel="prefetch" href="/tech-document/assets/js/5.44a12058.js"><link rel="prefetch" href="/tech-document/assets/js/6.237b9cc2.js"><link rel="prefetch" href="/tech-document/assets/js/7.d32d6951.js"><link rel="prefetch" href="/tech-document/assets/js/8.4049e9dd.js"><link rel="prefetch" href="/tech-document/assets/js/9.bec82895.js">
    <link rel="stylesheet" href="/tech-document/assets/css/0.styles.afad9826.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/tech-document/" class="home-link router-link-active"><!----> <span class="site-name">技术文档</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/tech-document/" class="nav-link">
  首页
</a></div><div class="nav-item"><a href="/tech-document/archive/" class="nav-link">
  文章归档
</a></div><div class="nav-item"><a href="/tech-document/css/" class="nav-link">
  HTML/CSS
</a></div><div class="nav-item"><a href="/tech-document/javascript/" class="nav-link">
  Javascript
</a></div><div class="nav-item"><a href="/tech-document/react/" class="nav-link router-link-active">
  React
</a></div><div class="nav-item"><a href="/tech-document/vue/" class="nav-link">
  Vue
</a></div><div class="nav-item"><a href="/tech-document/typescript/" class="nav-link">
  Typescript
</a></div><div class="nav-item"><a href="/tech-document/webpack/" class="nav-link">
  Webpack
</a></div><div class="nav-item"><a href="/tech-document/algorithm/" class="nav-link">
  算法
</a></div><div class="nav-item"><a href="/tech-document/network/" class="nav-link">
  网络知识
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="个人博客" class="dropdown-title"><span class="title">个人博客</span> <span class="arrow down"></span></button> <button type="button" aria-label="个人博客" class="mobile-dropdown-title"><span class="title">个人博客</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://blog.csdn.net/qq_39583550" target="_blank" rel="noopener noreferrer" class="nav-link external">
  CSDN
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://cjperfect.gitee.io/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  个人工具
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/tech-document/" class="nav-link">
  首页
</a></div><div class="nav-item"><a href="/tech-document/archive/" class="nav-link">
  文章归档
</a></div><div class="nav-item"><a href="/tech-document/css/" class="nav-link">
  HTML/CSS
</a></div><div class="nav-item"><a href="/tech-document/javascript/" class="nav-link">
  Javascript
</a></div><div class="nav-item"><a href="/tech-document/react/" class="nav-link router-link-active">
  React
</a></div><div class="nav-item"><a href="/tech-document/vue/" class="nav-link">
  Vue
</a></div><div class="nav-item"><a href="/tech-document/typescript/" class="nav-link">
  Typescript
</a></div><div class="nav-item"><a href="/tech-document/webpack/" class="nav-link">
  Webpack
</a></div><div class="nav-item"><a href="/tech-document/algorithm/" class="nav-link">
  算法
</a></div><div class="nav-item"><a href="/tech-document/network/" class="nav-link">
  网络知识
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="个人博客" class="dropdown-title"><span class="title">个人博客</span> <span class="arrow down"></span></button> <button type="button" aria-label="个人博客" class="mobile-dropdown-title"><span class="title">个人博客</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://blog.csdn.net/qq_39583550" target="_blank" rel="noopener noreferrer" class="nav-link external">
  CSDN
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://cjperfect.gitee.io/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  个人工具
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div> <!----></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>React</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/tech-document/react/" aria-current="page" class="sidebar-link">React中小知识点</a></li><li><a href="/tech-document/react/0浅谈副作用.html" class="sidebar-link">浅谈React副作用</a></li><li><a href="/tech-document/react/1浅谈Fiber是什么，解决了什么问题.html" class="sidebar-link">浅谈Fiber是什么，解决了什么问题</a></li><li><a href="/tech-document/react/2浅谈Fiber架构下React是如何更新的.html" class="sidebar-link">浅谈Fiber架构下React是如何更新的</a></li><li><a href="/tech-document/react/3浅谈ReactFiber是如何实现更新过程可控.html" class="sidebar-link">浅谈React Fiber如何实现更新过程可控</a></li><li><a href="/tech-document/react/Fiber工作原理.html" class="active sidebar-link">浅谈React Fiber工作原理</a></li><li><a href="/tech-document/react/React架构演变.html" class="sidebar-link">React架构演变</a></li><li><a href="/tech-document/react/阅读React源码前的序章.html" class="sidebar-link">阅读React源码前的序章</a></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><div class="custom-header" data-v-46893521><h1 class="title" data-v-46893521></h1> <div class="name" data-v-46893521>
    作者:
    <span data-v-46893521></span></div> <div class="categories" data-v-46893521>
    分类:
    </div> <div class="tags" data-v-46893521>
    标签:
    </div> <div class="date" data-v-46893521>
    创建时间:
    <span data-v-46893521></span></div></div> <h2 id="静态数据结构"><a href="#静态数据结构" class="header-anchor">#</a> 静态数据结构</h2> <p>每个 Fiber 节点对应一个组件，保存了该组件的类型，对应的 DOM 节点的对应信息。</p> <p>FiberRootNode 有且仅有一个，而 rootFiber 可以有多个，因为我们可以挂载多个应用（也就是多次调用<code>ReactDOM.render</code>）</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>age<span class="token punctuation">,</span> setAge<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">24</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span>
      chenjiang
      <span class="token punctuation">{</span>age<span class="token punctuation">}</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token operator">&lt;</span>App <span class="token operator">/</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;root&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>最终形成数据结构如下：</p> <p><img src="/tech-document/assets/img/1677589785791.5be7ac49.png" alt="1677589785791"></p> <h3 id="fiber-的数据结构"><a href="#fiber-的数据结构" class="header-anchor">#</a> Fiber 的数据结构</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">FiberNode</span><span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">tag</span><span class="token operator">:</span> WorkTag<span class="token punctuation">,</span> <span class="token literal-property property">pendingProps</span><span class="token operator">:</span> mixed<span class="token punctuation">,</span> <span class="token literal-property property">key</span><span class="token operator">:</span> <span class="token keyword">null</span> <span class="token operator">|</span> string<span class="token punctuation">,</span> <span class="token literal-property property">mode</span><span class="token operator">:</span> TypeOfMode</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Instance</span>

  <span class="token comment">// 组件的类型 FunctionComponent、classComponent、HostComponent（指的是DOM节点对应的Fiber节点）</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>tag <span class="token operator">=</span> tag<span class="token punctuation">;</span>

  <span class="token keyword">this</span><span class="token punctuation">.</span>key <span class="token operator">=</span> key<span class="token punctuation">;</span>

  <span class="token comment">// 大多数情况下于tag相同，使用React.memo包裹时候，elementType和tag不同</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>elementType <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 对于FunctionComponent，指函数本身</span>
  <span class="token comment">// 对于ClassComponent，指class</span>
  <span class="token comment">// 对于HostComponet，指的是DOM节点tagName</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>type <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 对于HostComponent来说指的是对应的真实的DOM节点</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>stateNode <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 以下属性用于连接其他Fiber节点形成Fiber树。</span>

  <span class="token comment">// 指向父fiber节点</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>return <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 指向第一个子fiber节点</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>child <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 指向第一个兄弟fiber节点</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>sibling <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>index <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

  <span class="token comment">// ref属性</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>ref <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 新传入的 props</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>pendingProps <span class="token operator">=</span> pendingProps<span class="token punctuation">;</span>

  <span class="token comment">// 之前的 props</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>memoizedProps <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 更新队列，用于暂存 setState 的值</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>updateQueue <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 之前的 state</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>memoizedState <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>dependencies <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token keyword">this</span><span class="token punctuation">.</span>mode <span class="token operator">=</span> mode<span class="token punctuation">;</span>

  <span class="token comment">// 保存本次更新会造成的DOM操作。比如删除，移动</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>flags <span class="token operator">=</span> NoFlags<span class="token punctuation">;</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>nextEffect <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token keyword">this</span><span class="token punctuation">.</span>firstEffect <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>lastEffect <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token keyword">this</span><span class="token punctuation">.</span>lanes <span class="token operator">=</span> NoLanes<span class="token punctuation">;</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>childLanes <span class="token operator">=</span> NoLanes<span class="token punctuation">;</span>

  <span class="token comment">//用于链接新树和旧树；旧-&gt;新，新-&gt;旧</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>alternate <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="动态的工作单元"><a href="#动态的工作单元" class="header-anchor">#</a> 动态的工作单元</h2> <p>Fiber 可以理解成一个工作单元，每次执行完一个工作单元，react 就会检查还剩余多少时间，如果没有就把控制权交还给浏览器。React Fiber 与浏览器的核心交互过程如下：</p> <p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/78a602cbc87342628ace49abb5d20c39~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.awebp" alt="undefined"></p> <p>首先 React 向浏览器请求调度，浏览器在一帧中如果还有空闲时间，会去判断是否存在待执行任务，不存在就直接将控制权交给浏览器，如果存在就会执行对应的任务，执行完成后会判断是否还有时间，有时间且有待执行任务则会继续执行下一个任务，否则就会将控制权交给浏览器。</p> <p>Fiber 可以被理解为划分一个个更小的工作单元，它是把一个大任务拆分为了很多个小块任务，一个小块任务的执行必须是一次完成的，不能出现暂停，但是一个小块任务执行完后可以移交控制权给浏览器去响应用户，从而不用等待大任务一直执行完成再去响应用户。</p> <h2 id="架构-双缓存工作机制"><a href="#架构-双缓存工作机制" class="header-anchor">#</a> 架构（双缓存工作机制）</h2> <h3 id="什么是双缓存"><a href="#什么是双缓存" class="header-anchor">#</a> 什么是双缓存</h3> <p>当我们用<code>canvas</code>绘制动画，每一帧绘制前都会调用<code>ctx.clearRect</code>清除上一帧的画面。如果当前帧画面计算量比较大，导致清除上一帧画面到绘制当前帧画面之间有较长间隙，就会出现白屏闪烁。</p> <p>为了解决这个问题，我们可以在<code>内存中</code>绘制当前帧动画，绘制完毕后直接用当前帧替换上一帧画面，由于省去了两帧替换间的计算时间，不会出现从白屏到出现画面的闪烁情况。</p> <p>这种<strong>在内存中构建并直接替换</strong>的技术叫做<a href="https://link.juejin.cn?target=https%3A%2F%2Fbaike.baidu.com%2Fitem%2F%E5%8F%8C%E7%BC%93%E5%86%B2" target="_blank" rel="noopener noreferrer">双缓存<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>。</p> <p><code>React</code>使用“双缓存”来完成<code>Fiber树</code>的构建与替换——对应着<code>DOM树</code>的创建与更新。</p> <h3 id="双缓存-fiber-树"><a href="#双缓存-fiber-树" class="header-anchor">#</a> 双缓存 Fiber 树</h3> <p>React 中存在两棵树，一颗为<code>current Fiber tree</code>，另外一颗为<code>workInProgress Fiber tree</code>。</p> <ul><li><code>current Fiber tree</code>也就是当前页面中显示内容对应的 Fiber 树，每个 Fiber 节点成为 current fiber。</li> <li><code>workInProgress Fiber tree</code>正在内存中构建的 Fiber 树。</li></ul> <p>两颗树的 fiber 节点是通过<code>alternate</code>属性进行连接的。</p> <div class="language-js extra-class"><pre class="language-js"><code>currentFiber<span class="token punctuation">.</span>alternate <span class="token operator">===</span> workInProgressFiber<span class="token punctuation">;</span>
workInProgressFiber<span class="token punctuation">.</span>alternate <span class="token operator">===</span> currentFiber<span class="token punctuation">;</span>
</code></pre></div><p>React 的根节点（FiberRootNode）通过 current 指针在不同的 Fiber 树的 rootFiber 间切换来实现 Fiber 树的切换。</p> <p><img src="/tech-document/assets/img/animate.c506839f.gif" alt="动画"></p> <h4 id="fiber-树的构建-挂载阶段、更新阶段"><a href="#fiber-树的构建-挂载阶段、更新阶段" class="header-anchor">#</a> Fiber 树的构建（挂载阶段、更新阶段）</h4> <p>再次强调：FiberRootNode 有且仅有一个，而 rootFiber 可以有多个，因为我们可以挂载多个应用（也就是多次调用<code>ReactDOM.render</code>）</p> <p>以下代码为例：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>age<span class="token punctuation">,</span> setAge<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">24</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div
      onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token function">setAge</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">}</span>
    <span class="token operator">&gt;</span>
      <span class="token punctuation">{</span>age<span class="token punctuation">}</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token operator">&lt;</span>App <span class="token operator">/</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;root&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p><strong>挂载阶段（mount 阶段）</strong></p> <p>当<code>首次调用ReactDOM.render</code>就会创建<code>FiberRootNode</code>，每次调用<code>ReactDOM.render</code>就会创建当前应用的根节点<code>RootFiber</code>，由于在首屏渲染之前页面是空白的，因此<code>RootFiber</code>不存在子节点。</p> <p><img src="" alt="1677676221915"></p> <p><strong>挂载阶段流程如下（首屏渲染）</strong></p> <p>首先创建 fiber 树的根节点<code>RootFiber</code>，在两棵树之间都存在的 Fiber 节点用<code>alternate</code>连接，接下来采用深度遍历的方式创建 Fiber 树，当<code>workInProgress Fiber tree</code>完成了渲染，最后 FiberRootNode 的 current 指针就指向<code>workInProgress Fiber tree</code>的根节点，此时就变成<code>current Fiber tree</code>。</p> <p><img src="/tech-document/assets/img/animate-1677677631515.d3e3cbfa.gif" alt="animate"></p> <p><strong>更新阶段 （update 阶段）</strong></p> <p>每次触发更新都会重新创建一颗<code>workInProgress Fiber Tree</code>，<code>current Fiber</code>与本次更新返回的<code>JSX</code>做对比，生成<code>workInProgress Fiber</code>的过程就是 diff 算法，update 阶段与 mount 阶段，最大的区别就是是否有 diff 算法。</p> <p><img src="/tech-document/assets/img/animate-1677679212081.3e1e4a4e.gif" alt="animate"></p> <p>参考文章：</p> <ul><li><a href="https://juejin.cn/post/6844904202104209415" target="_blank" rel="noopener noreferrer">https://juejin.cn/post/6844904202104209415<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://juejin.cn/post/6943896410987659277" target="_blank" rel="noopener noreferrer">https://juejin.cn/post/6943896410987659277<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div> <footer class="page-edit"><!----> <!----></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/tech-document/react/3浅谈ReactFiber是如何实现更新过程可控.html" class="prev">
        浅谈React Fiber如何实现更新过程可控
      </a></span> <span class="next"><a href="/tech-document/react/React架构演变.html">
        React架构演变
      </a>
      →
    </span></p></div> </main></div><div class="global-ui"><!----><!----></div></div>
    <script src="/tech-document/assets/js/app.7336957d.js" defer></script><script src="/tech-document/assets/js/2.4e1184b4.js" defer></script><script src="/tech-document/assets/js/4.254b04cb.js" defer></script><script src="/tech-document/assets/js/12.c2ba2865.js" defer></script>
  </body>
</html>
